package org.expressme.ant;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;

/**
 * Generate classes of Action Script from JavaBeans.
 * 
 * @author Michael Liao (askxuefeng@gmail.com)
 */
public class JavaBean2ActionScript {

    String toActionScript(Class<?> clazz, boolean orderByName) {
        Method[] ms = clazz.getMethods();
        // find all getters:
        List<Method> getters = new ArrayList<Method>(ms.length);
        for (Method m : ms) {
            getters.add(m);
        }
        for (Iterator<Method> it = getters.iterator();it.hasNext();) {
            Method m = it.next();
            if (! isSupportedGetter(m, ms) || ! isNormal(m)) {
                it.remove();
            }
        }
        // find valid getters which have corresponding setters:
        for (Iterator<Method> it = getters.iterator();it.hasNext();) {
            Method m = it.next();
            String getter = m.getName();
            String setterName = getter.startsWith("get")
                    ? "set" + getter.substring(3)
                    : "set" + getter.substring(2);
            boolean found = false;
            try {
                Method setter = clazz.getMethod(setterName, m.getReturnType());
                if (isNormal(setter) && setter.getReturnType().equals(void.class))
                    found = true;
            }
            catch(SecurityException e) {
                throw new RuntimeException(e);
            }
            catch(NoSuchMethodException e) {
            }
            if (! found)
                it.remove();
        }
        if (orderByName) {
            Method[] arr = getters.toArray(new Method[getters.size()]);
            Arrays.sort(arr,
                    new Comparator<Method>() {
                        public int compare(Method o1, Method o2) {
                            return o1.getName().compareTo(o2.getName());
                        }
                    }
            );
            getters = Arrays.asList(arr);
        }
        StringBuilder sb = new StringBuilder(1024);
        for (Method m : getters) {
            sb.append("        public var ")
              .append(getGetterName(m))
              .append(" : ")
              .append(getMapping(m.getReturnType()))
              .append(";\r\n");
        }
        String s = Utils.loadResource("org/expressme/ant/Bean.as");
        s = s.replace("${PACKAGE}", clazz.getPackage().getName());
        s = s.replace("${CLASS}", clazz.getSimpleName());
        s = s.replace("${REMOTE_CLASS}", clazz.getName());
        s = s.replace("${PROPERTIES}", sb.toString());
        return s;
    }

    String getMapping(Class<?> t) {
        if (t.isArray())
            return "Array";
        return Utils.getMapping(t);
    }

    boolean isSupportedGetter(Method m, Method[] all) {
        if (m.getParameterTypes().length>0)
            return false;
        if (getMapping(m.getReturnType())==null)
            return false;
        String name = m.getName();
        if (name.startsWith("get") && name.length()>3) {
            return true;
        }
        if (name.startsWith("is") && name.length()>2) {
            Class<?> ret = m.getReturnType();
            return ret.equals(boolean.class) || ret.equals(Boolean.class);
        }
        return false;
    }

    boolean isNormal(Method method) {
        int m = method.getModifiers();
        return ! Modifier.isStatic(m);
    }

    String getGetterName(Method m) {
        String name = m.getName();
        if (name.startsWith("get"))
            return Character.toLowerCase(name.charAt(3)) + name.substring(4);
        if (name.startsWith("is"))
            return Character.toLowerCase(name.charAt(2)) + name.substring(3);
        throw new IllegalArgumentException("Method is not a valid getter.");
    }

}
